package cn.xinfei.xdecision.engine.runner.executor.strategy.node;

import cn.xinfei.xdecision.common.model.component.guiderule.RuleInfo;
import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.enginex.model.EngineNodeModel;
import cn.xinfei.xdecision.common.model.enginex.model.NodeJsonModel;
import cn.xinfei.xdecision.common.model.enginex.po.EngineNode;
import cn.xinfei.xdecision.common.utils.constant.Constants;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.NodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RuleComponentHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RuleGroupNodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.handler.RulePostProcessHandler;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineNodeRunner;
import cn.xinfei.xdecision.engine.runner.service.RuleNodeService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;

import static cn.xinfei.xdecision.constant.EngineResultEnum.EXCEPTION_NODE_NULL_END;
import static cn.xinfei.xdecision.engine.runner.executor.handler.RulePostProcessHandler.ACTION_CACHE_PRE;

@Slf4j
@Service
public class RuleGroup extends EngineNodeRunner {

    @Autowired
    private RuleNodeService ruleNodeService;

    @Resource
    private RuleGroupNodeHandler ruleGroupNodeHandler;

    @Resource
    private RuleComponentHandler ruleComponentHandler;

    @Resource
    private RulePostProcessHandler rulePostProcessHandler;

    private static final String RULE_GROUP_CACHE_PRE = "rule_group_cache_pre_";


    @Autowired
    @Qualifier("bizProcessorThreadPool")
    public ExecutorService bizProcessorThreadPool;

    @Override
    public String getServiceName() {
        return EngineNodeRunner.PRE + NodeTypeEnum.RULE_BASE.getType();
    }

    @Override
    public void after(NodeHandler nodeHandler, StateTransmitModel stateTransmitModel, Map nodeOutput, Map nodeInput) {
        //将规则集的节点输出，补充到stateTransmitModel对象中
        super.after(nodeHandler, stateTransmitModel, nodeOutput, nodeInput);
    }


    public void getNodeFieldValue(NodeHandler nodeHandler) throws Exception {
        //归则集节点不进行节点级别的预加载
    }

    @Override
    public void before(NodeHandler nodeHandler) {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String engineCode = engineNode.getEngineCode();


        String nodeJson = engineNode.getNodeJson();
        if (StringUtils.isEmpty(nodeJson)) {
            log.error("RuleGroup node json is null");
            return;
        }

        NodeJsonModel nodeJsonModel = JSONObject.parseObject(nodeJson, NodeJsonModel.class);
        String nodeCode = engineNode.getNodeCode();

        if (null != nodeJson) {
            int groupType = nodeJsonModel.getGroupType();
            List<EngineNodeModel> componentList = nodeJsonModel.getComponentList();

            List<RuleInfo> ruleInfoList = ruleNodeService.getRuleFromJsonArray(componentList);

            //缓存规则信息
//            String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + groupType + "_" + nodeCode;
            nodeHandler.put(RULE_GROUP_CACHE_PRE + nodeCode, ruleInfoList);
            nodeHandler.put(ACTION_CACHE_PRE + nodeCode, rulePostProcessHandler.combineAction(ruleInfoList));
        }
    }

    /**
     * "rules": [{
     * "id": 456,
     * "parentId": 22,
     * "code": "shiyusenScriptTest",
     * "name": "shiyusenScriptTest",
     * "ruleVersionId": 9,
     * "versionCode": "V:0",
     * "description": "初始版本",
     * "difficulty": 3
     * }]
     */
    @Override
    public Map<String, FieldInfoVo> getInputFieldInfo(NodeHandler nodeHandler) {

        EngineNode engineNode = nodeHandler.getEngineNode();
        String nodeCode = engineNode.getNodeCode();
        String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + nodeCode;
        List<RuleInfo> ruleInfoList = (List<RuleInfo>) nodeHandler.get(ruleInfoCacheKey);

        Map<String, FieldInfoVo> inputResults = new HashMap<>();
        for (int i = 0; i < ruleInfoList.size(); i++) {
            RuleInfo ruleInfo = ruleInfoList.get(i);
            Map<String, FieldInfoVo> inputResult = ruleComponentHandler.extractorInput(ruleInfo);
            inputResults.putAll(inputResult);
        }
        return inputResults;
    }


    @Override
    public StateTransmitModel runNode(NodeHandler nodeHandler) throws Exception {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String json = engineNode.getNodeJson();
        if (StringUtils.isEmpty(json)) {
            log.error("RuleGroup node json is null");
            return XDecisionContext.getContext().getStateContext().setEngineResultEnum(EXCEPTION_NODE_NULL_END);
        }
        StateTransmitModel stateTransmitModel = XDecisionContext.getContext().getStateContext();
        JSONObject nodeJson = JSONObject.parseObject(json);
        int groupType = nodeJson.getInteger("groupType") == null ? Constants.ruleNode.EXECUTEGROUP : nodeJson.getInteger("groupType");
        // 规则块命中执行结果集合，含分数
        String nodeCode = engineNode.getNodeCode();
        String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + nodeCode;
        List<RuleInfo> ruleInfoList = (List<RuleInfo>) nodeHandler.get(ruleInfoCacheKey);

        // 互斥组(串行)
        if (groupType == Constants.ruleNode.MUTEXGROUP) {
            //监控中心--循环获取策略层面的快照信息
            ruleGroupNodeHandler.serialRule(nodeHandler,stateTransmitModel, nodeCode, ruleInfoList);
        }
        // 执行组(并行)
        else if (groupType == Constants.ruleNode.EXECUTEGROUP) {
            //监控中心--循环获取策略层面的快照信息
            ruleGroupNodeHandler.parallelRule(nodeHandler,stateTransmitModel, nodeCode, ruleInfoList);
        }
        //nodeHandler提供了一个回调钩子，解决规则模块的特殊场景
        rulePostProcessHandler.postProcess(stateTransmitModel, nodeHandler);
        rulePostProcessHandler.processRejectCode(stateTransmitModel, ruleInfoList);
        //处理动作配置类
        try {
            bizProcessorThreadPool.execute(() -> rulePostProcessHandler.actionPostProcess(nodeHandler, nodeCode));
        }catch (Exception e){
            log.error("规则组动作添加线程异常,msg={}",e.getMessage(),e);
            //todo 线程池队列，告警
        }
        return stateTransmitModel;
    }




    /**
     * 定制化实现:规则不能返回策略输出
     * 定制化实现:规则不能返回策略输出
     * 定制化实现:规则不能返回策略输出
     * 规则的输出，需要根据命中的规则块决定输出那些，因此
     * 规则不能返回策略输出，如果返回会被NodeHandler执行输出逻辑
     * @param nodeHandler
     * @return
     */
    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(NodeHandler nodeHandler) {
        EngineNode engineNode = nodeHandler.getEngineNode();
        String nodeCode = engineNode.getNodeCode();
        String engineCode = engineNode.getEngineCode();

//        规则不需要提取组件内的输出，只需要提取节点中的终止输出
//        Map<String, StrategyOutput> outputResult = getTerminalOutputFieldInfo(nodeHandler);

//        Map<String, StrategyOutput> strategyOutputMap = super.getOutputFieldInfo(nodeHandler);
//
//        String ruleInfoCacheKey = RULE_GROUP_CACHE_PRE + nodeCode;
//
//        List<RuleInfo> ruleInfoList = (List<RuleInfo>) nodeHandler.get(ruleInfoCacheKey);
//
//        Map<String, StrategyOutput> outputResult = ruleComponentHandler.extractorOutput(ruleInfoList);
//
//        strategyOutputMap.putAll(outputResult);

//        return strategyOutputMap;


        return new HashMap<>();
    }
}
